using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using LDNS.SDK.Commands.Models; // 添加对Model命名空间的引用

namespace LDNS.SDK.Commands
{
    /// <summary>
    /// 命令注册表，用于注册、解析和执行命令
    /// 作者：huobing
    /// </summary>
    public static class CommandRegistry
    {
        private static readonly Dictionary<string, Func<IBaseCommand>> _map = new Dictionary<string, Func<IBaseCommand>>();
        
        /// <summary>
        /// 获取所有已注册的命令列表
        /// </summary>
        public static IEnumerable<IBaseCommand> Commands
        {
            get
            {
                var commands = new List<IBaseCommand>();
                var seenNames = new HashSet<string>();

                foreach (var key in _map.Keys)
                {
                    IBaseCommand command = _map[key]();
                    // 尝试将命令对象转换为IBaseCommand

                    string name = command.Name;
                    if (!string.IsNullOrEmpty(name) && !seenNames.Contains(name))
                    {
                        seenNames.Add(name);
                        commands.Add(command);
                    }
                }

                return commands;
            }
        }

        /// <summary>
        /// 静态构造函数，注册所有内置命令
        /// </summary>
        static CommandRegistry()
        {
            // 注册状态命令
            Register<StatusCommand, StatusResult>();
            Register<GetStartTimeCommand, GetStartTimeResult>();

            // 注册操作命令
            Register<StartCommand, DefaultCommandResult>();
            Register<StopCommand, DefaultCommandResult>();
            Register<RestartCommand, DefaultCommandResult>();
            // ExitCommand已移除

            //注册配置操作命令
            Register<GetConfigCommand, GetConfigResult>();
            Register<SetConfigCommand, DefaultCommandResult>();

            // 注册缓存操作命令
            Register<ClearCacheCommand, ClearCacheResult>();
            Register<GetCacheStatsCommand, GetCacheStatsResult>();
            Register<GetStatisticsCommand, GetStatisticsResult>();

            // 注册域名操作命令
            Register<AddCommand, DefaultCommandResult>();
            Register<RemoveCommand, DefaultCommandResult>();
            Register<ListRecordsCommand, DnsRecordsResult>();

            // 注册上游路由服务操作命令
            Register<ListUpstreamCommand, ListUpstreamResult>();
            Register<SetUpstreamMainDomainCommand, DefaultCommandResult>();

            // 注册帮助命令
            Register<HelpCommand, HelpResult>();
        }

        /// <summary>
        /// 注册命令
        /// </summary>
        /// <typeparam name="T">命令类型</typeparam>
        /// <typeparam name="TResult">命令结果类型</typeparam>
        public static void Register<T, TResult>() where T : BaseCommand<TResult>, new() where TResult : BaseCommandResult, new()
        {
            var command = new T();
            // 直接存储对象，避免类型转换问题
            _map[command.Name.ToUpper()] = () => new T();

            // 注册别名
            foreach (var alias in command.Aliases)
            {
                _map[alias.ToUpper()] = () => new T();
            }
        }

        /// <summary>
        /// 尝试解析命令（非泛型版本，返回IBaseCommand接口）
        /// 这样可以通过非泛型接口引用任何命令对象，避免泛型类型转换问题
        /// </summary>
        /// <param name="line">命令行</param>
        /// <param name="command">命令对象（IBaseCommand接口）</param>
        /// <param name="args">命令参数</param>
        /// <param name="error">错误信息</param>
        /// <returns>是否成功解析</returns>
        public static bool TryResolve(string line, out IBaseCommand? command, out string[] args, out string error)
        {
            command = null;
            args = [];
            error = string.Empty;

            if (string.IsNullOrWhiteSpace(line))
            {
                error = "命令不能为空";
                return false;
            }

            var parts = ParseCommandLine(line);
            if (parts.Length == 0)
            {
                error = "无效的命令格式";
                return false;
            }

            var cmdName = parts[0].ToUpper();
            args = parts.Length > 1 ? parts[1..] : Array.Empty<string>();

            if (!_map.TryGetValue(cmdName, out var factory))
            {
                error = $"未知命令: {cmdName}";
                return false;
            }

            // 创建命令对象并尝试转换为IBaseCommand接口
            command = factory();
 
            // 直接调用IBaseCommand接口的Validate方法
            if (!command.Validate(args, out error))
            {
                command = null;
                return false;
            }
            
            return true;
        }

        /// <summary>
        /// 解析命令行参数
        /// </summary>
        /// <param name="line">命令行</param>
        /// <returns>解析后的参数数组</returns>
        public static string[] ParseCommandLine(string line)
        {
            // 正则表达式用于解析命令行参数，支持引号和转义
            var pattern = @"(\""([^\""\\]|\\.)*\""|[^\s\""])+";
            var matches = Regex.Matches(line, pattern);
            var parts = new string[matches.Count];

            for (int i = 0; i < matches.Count; i++)
            {
                var value = matches[i].Value;
                // 去除引号
                if (value.StartsWith("\"") && value.EndsWith("\""))
                {
                    value = value.Substring(1, value.Length - 2);
                    // 替换转义字符
                    value = Regex.Replace(value, @"\\(.)", "$1");
                }
                parts[i] = value;
            }
            return parts;
        }

        /// <summary>
        /// 获取所有命令的帮助信息
        /// </summary>
        /// <returns>命令帮助信息表格</returns>
        public static string GetHelpTable()
        {
            var commands = new List<IBaseCommand>();
            var seenNames = new HashSet<string>();

            foreach (var key in _map.Keys)
            {
                var cmdObj = _map[key]();
                if (cmdObj is IBaseCommand baseCommand)
                {
                    string name = baseCommand.Name;
                    if (!string.IsNullOrEmpty(name) && !seenNames.Contains(name))
                    {
                        seenNames.Add(name);
                        commands.Add(baseCommand);
                    }
                }
            }

            // 创建命令信息列表用于排序
            var commandInfos = new List<CommandInfo>();
            foreach (var cmdObj in commands)
            {
                var info = GetCommandInfo(cmdObj);
                if (info != null)
                {
                    commandInfos.Add(info);
                }
            }

            // 按名称排序
            commandInfos.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));

            var table = new StringBuilder();
            table.AppendLine("命令列表:");
            table.AppendLine(new string('-', 80));
            table.AppendLine($"{"命令",-20} {"格式",-30} {"描述",-20} {"权限",-10}");
            table.AppendLine(new string('-', 80));

            foreach (var info in commandInfos)
            {
                table.AppendLine($"{info.Name,-20} {info.Format,-30} {info.Description,-20} {info.Permission,-10}");
            }

            table.AppendLine(new string('-', 80));
            table.AppendLine("使用 'HELP 命令名' 获取特定命令的详细帮助");

            return table.ToString();
        }

        /// <summary>
        /// 命令信息辅助类
        /// </summary>
        private class CommandInfo
        {
            public string Name { get; set; } = string.Empty;
            public string Format { get; set; } = string.Empty;
            public string Description { get; set; } = string.Empty;
            public string Permission { get; set; } = string.Empty;
        }

        /// <summary>
        /// 获取命令对象的信息
        /// </summary>
        /// <param name="cmdObj">命令对象</param>
        /// <returns>命令信息</returns>
        private static CommandInfo? GetCommandInfo(IBaseCommand cmdObj)
        {
            if (cmdObj == null)
                return null;

            var info = new CommandInfo
            {
                Name = cmdObj.Name ?? string.Empty,
                Format = cmdObj.Format ?? string.Empty,
                Description = cmdObj.Description ?? string.Empty,
                Permission = cmdObj.Permission.ToString() ?? string.Empty
            };

            return info;
        }
    }
}